﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace PaperCut.Classes
{
    public class BezierHelper
    {
        static int steps = 10;
        public static void SetStep(int step)
        {
            steps = step;
        }
        public static bool BezierIntersect(Point point1, Point point2, Point point3, Point lpt1, Point lpt2)
        {
            int verticesCount = (3 - 2) * steps;
            Point[] vertices = new Point[verticesCount];

            Point? previous = null;

            float amount = 0f;
            for (int j = 0; j <= steps - 1; j++)
            {
                double x = Math.Pow(1 - amount, 2) * point3.X + 2.0f * (1 - amount) * amount * point2.X + amount * amount * point1.X;
                double y = Math.Pow(1 - amount, 2) * point3.Y + 2.0f * (1 - amount) * amount * point2.Y + amount * amount * point1.Y;
                Point pnt = new Point(x, y);
                if (previous != null)
                {
                    var pt = GeometryHelper.LinesIntersect(previous.Value, pnt, lpt1, lpt2);
                    if (pt != null) return true;
                }
                previous = new Point(x, y);
                amount += 1f / (steps - 1);
            }
            return false;
        }

        public static double GetCubicBezierPointAt(double t, double start, double control_1, double control_2, double end)
        {
            /* Formula from Wikipedia article on Bezier curves. */
            return start * (1.0 - t) * (1.0 - t) * (1.0 - t)
                   + 3.0 * control_1 * (1.0 - t) * (1.0 - t) * t
                   + 3.0 * control_2 * (1.0 - t) * t * t
                   + end * t * t * t;
        }
        public static Point GetCubicBezierPointAt(double t, Point start, Point control_1, Point control_2, Point end)
        {
            /* Formula from Wikipedia article on Bezier curves. */
            double X = start.X * (1.0 - t) * (1.0 - t) * (1.0 - t)
                    + 3.0 * control_1.X * (1.0 - t) * (1.0 - t) * t
                    + 3.0 * control_2.X * (1.0 - t) * t * t
                    + end.X * t * t * t;
            double Y = start.Y * (1.0 - t) * (1.0 - t) * (1.0 - t)
                   + 3.0 * control_1.Y * (1.0 - t) * (1.0 - t) * t
                   + 3.0 * control_2.Y * (1.0 - t) * t * t
                   + end.Y * t * t * t;
            return new Point(X, Y);
        }

        public static double GetQuadraticBezierPointAt(double t, double start, double control_1, double end)
        {
            /* Formula from Wikipedia article on Bezier curves. */
            return start * (1.0 - t) * (1.0 - t)
                   + 2.0 * control_1 * (1.0 - t) * t
                   + end * t * t;
        }

        public static Point GetQuadraticBezierPointAt(double t, Point start, Point control_1, Point end)
        {
            /* Formula from Wikipedia article on Bezier curves. */
            double X = start.X * (1.0 - t) * (1.0 - t)
                   + 2.0 * control_1.X * (1.0 - t) * t
                   + end.X * t * t;
            double Y = start.Y * (1.0 - t) * (1.0 - t)
                   + 2.0 * control_1.Y * (1.0 - t) * t
                   + end.Y * t * t;
            return new Point(X, Y);
        }

        public static double GetCubicBezierLength(Point A, Point B, Point C, Point D)
        {
            double t;
            int i;
           
            Point dot = new Point();
            Point previous_dot = new Point(0, 0);
            double length = 0.0;
           
            for (i = 0; i <= steps; i++)
            {
                t = (double)i / (double)steps;
                dot.X = GetCubicBezierPointAt(t, A.X, B.X,
                               C.X, D.X);
                dot.Y = GetCubicBezierPointAt(t, A.Y, B.Y,
                               C.Y, D.Y);
                if (i > 0)
                {
                    double x_diff = dot.X - previous_dot.X;
                    double y_diff = dot.Y - previous_dot.Y;
                    length += Math.Sqrt(x_diff * x_diff + y_diff * y_diff);
                }
                previous_dot = dot;
            }
            return length;
        }
        public static double GetQuadraticBezierLength(Point A, Point B, Point C)
        {
            double t;
            int i;
            
            Point dot = new Point();
            Point previous_dot = new Point(0, 0);
            double length = 0.0;
            
            for (i = 0; i <= steps; i++)
            {
                t = (double)i / (double)steps;
                dot.X = GetQuadraticBezierPointAt(t, A.X, B.X,
                               C.X);
                dot.Y = GetQuadraticBezierPointAt(t, A.Y, B.Y,
                               C.Y);
                if (i > 0)
                {
                    double x_diff = dot.X - previous_dot.X;
                    double y_diff = dot.Y - previous_dot.Y;
                    length += Math.Sqrt(x_diff * x_diff + y_diff * y_diff);
                }
                previous_dot = dot;
            }
            return length;
        }
    }
}
